#ifndef WIN32
#include <gcrypt.h>
#endif
#include <stdio.h>
#include <stdlib.h>

#include "crypt.h"
#ifndef WIN32
gcry_cipher_hd_t cipher1;
#endif
unsigned char *elog_crypt_key = NULL;
int buffer = 1024;

unsigned char iv[16] =
    { 'a', 'g', 'z', 'e', 'Q', '5', 'E', '7', 'c', '+', '*', 'G', '1', 'D',
	'u', '='
};

unsigned char ctr[16] =
    { 'd', 'g', '4', 'e', 'J', '5', '3', 'l', 'c', '-', '!', 'G', 'z', 'A',
	'z', '='
};

int setBuffer(int buf)
{
	if (buf == 0)
		return buffer;
	else
		buffer = buf;
	return 0;
}
void encryptText(unsigned char *text, unsigned int len)
{
#ifndef WIN32
	gcry_error_t error1 =
	    gcry_cipher_open(&cipher1, GCRY_CIPHER_AES256,
			     GCRY_CIPHER_MODE_CTR, 0);
	error1 = gcry_cipher_setiv(cipher1, &iv, 16);
	error1 = gcry_cipher_setctr(cipher1, &ctr, 16);
	error1 = gcry_cipher_setkey(cipher1, elog_crypt_key, 32);
	gcry_cipher_encrypt(cipher1, text, (size_t) len, NULL, 0);
	gcry_cipher_close(cipher1);
#endif
}
void decryptText(unsigned char *text, unsigned int len)
{
#ifndef WIN32
	gcry_error_t error1 =
	    gcry_cipher_open(&cipher1, GCRY_CIPHER_AES256,
			     GCRY_CIPHER_MODE_CTR, 0);
	error1 = gcry_cipher_setiv(cipher1, &iv, 16);
	error1 = gcry_cipher_setctr(cipher1, &ctr, 16);
	error1 = gcry_cipher_setkey(cipher1, elog_crypt_key, 32);
	gcry_cipher_decrypt(cipher1, text, (size_t) len, NULL, 0);
	gcry_cipher_close(cipher1);
#endif
}
void encryptFile(const char *fileName)
{
#ifndef WIN32
	gcry_error_t error1 =
	    gcry_cipher_open(&cipher1, GCRY_CIPHER_AES256,
			     GCRY_CIPHER_MODE_CTR, 0);
	error1 = gcry_cipher_setiv(cipher1, &iv, 16);
	error1 = gcry_cipher_setctr(cipher1, &ctr, 16);
	error1 = gcry_cipher_setkey(cipher1, elog_crypt_key, 32);


	FILE *file1 = fopen(fileName, "rb+");	//open file for read/write binary
	fseek(file1, 0, SEEK_END);
	int len = ftell(file1);
	fseek(file1, 0, SEEK_SET);

	int c = 0;
	while (c < len) {
		fpos_t *loc = (fpos_t *) malloc(sizeof(fpos_t));
		fgetpos(file1, loc);
		int bytesRead;
		unsigned char *tmp;
		tmp =
		    (unsigned char *) malloc(sizeof(unsigned char) *
					     (buffer * 1024));
		if (ftell(file1) + (buffer * 1024) < len)
			bytesRead =
			    fread(tmp, sizeof *tmp, buffer * 1024, file1);
		else
			bytesRead =
			    fread(tmp, sizeof *tmp, (len - ftell(file1)),
				  file1);

		gcry_cipher_encrypt(cipher1, tmp, (size_t) bytesRead, NULL,
				    0);

		//for (int q=0; q < bytesRead; ++q)
		//      tmp[q]-=1;


		/*do your stuff */
		fsetpos(file1, loc);	//moving back for an overwrite!


		fwrite(tmp, 1, (size_t) bytesRead, file1);	//should overwrite, as long as we move the file ptr back!

		fgetpos(file1, loc);


		c += bytesRead;
		free(tmp);
		free(loc);
	}
	fclose(file1);
	gcry_cipher_close(cipher1);
#endif
}
void decryptFile(char *fileName)
{
#ifndef WIN32
	gcry_error_t error1 =
	    gcry_cipher_open(&cipher1, GCRY_CIPHER_AES256,
			     GCRY_CIPHER_MODE_CTR, 0);
	error1 = gcry_cipher_setiv(cipher1, &iv, 16);
	error1 = gcry_cipher_setctr(cipher1, &ctr, 16);
	error1 = gcry_cipher_setkey(cipher1, elog_crypt_key, 32);

	FILE *file1 = fopen(fileName, "rb+");	//open file for read/write binary
	fseek(file1, 0, SEEK_END);
	int len = ftell(file1);
	fseek(file1, 0, SEEK_SET);

	int c = 0;
	while (c < len) {
		fpos_t *loc = (fpos_t *) malloc(sizeof(fpos_t));
		fgetpos(file1, loc);
		int bytesRead;
		unsigned char *tmp;
		tmp =
		    (unsigned char *) malloc(sizeof(unsigned char) *
					     (buffer * 1024));
		if (ftell(file1) + (buffer * 1024) < len)
			bytesRead =
			    fread(tmp, sizeof *tmp, buffer * 1024, file1);
		else
			bytesRead =
			    fread(tmp, sizeof *tmp, (len - ftell(file1)),
				  file1);

		gcry_cipher_decrypt(cipher1, tmp, (size_t) bytesRead, NULL,
				    0);

		//for (int q=0; q < bytesRead; ++q)
		//      tmp[q]-=1;


		/*do your stuff */
		fsetpos(file1, loc);	//moving back for an overwrite!


		fwrite(tmp, 1, (size_t) bytesRead, file1);	//should overwrite, as long as we move the file ptr back!

		fgetpos(file1, loc);


		c += bytesRead;
		free(tmp);
		free(loc);
	}
	fclose(file1);
	gcry_cipher_close(cipher1);
#endif
}

// vvv needs to be updated to this:
/*

*/
unsigned char *createKey(char *password, int keyLen)
{
	if (elog_crypt_key != NULL)
		free(elog_crypt_key);
	unsigned char *key = elog_crypt_key =
	    (unsigned char *) malloc(sizeof(unsigned char) * (keyLen / 8));



	int c;

	for (c = 0; c < keyLen / 8; ++c)
		key[c] = 0;


	int powersof2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };

	int len_str = strlen(password);
	key[(keyLen / 8) - 1] = len_str;
	int size_str = len_str * (sizeof *password) * 8;
	int skip = (keyLen - 5) / size_str;
	//^^num of bits..
	int current = 0;
	for (c = 0; c < len_str; ++c) {
		int j;
		int remainder = password[c];
		for (j = 0; j < 8; ++j) {
			int mod = remainder % powersof2[7 - j];

			if (mod != remainder)	//if it divided for 1
			{
				remainder = mod;
				int i = current / 8;
				int pow = current % 8;
				key[i] += powersof2[7 - pow];
			}
			current += skip;
		}

	}
	return key;
}
unsigned char *viewKey()
{
	return elog_crypt_key;
}
void setKey(unsigned char *key)
{
	elog_crypt_key = key;
}
